<template>
    <PopList :title="'元胞网格'" :showButton="true" @close="destroy" @ok="createGrid">
        <LabelInput v-model="cellSize" :inputType="'number'" :label="'单元格大小(米)'" :min="10" :max="100"></LabelInput>
        <LabelInput v-model="gridSize" :inputType="'number'" :label="'网格大小(米)'" :min="100" :max="2000"></LabelInput>
    </PopList>
    <PopList :title="'起火'"
             :showButton="true"
             @ok="onFire"
             :showLeftButton="true"
             :leftButton="'重置'"
             @close="reset">
        <LabelInput v-model="spreadMaxTimes" :unit="'次'" :inputType="'number'" :label="'计算次数'" :min="1"></LabelInput>
        <LabelInput v-model="spreadFrequency" :unit="'s'" :inputType="'number'" :label="'频率'" :min="1"></LabelInput>
        <LabelInput v-model="fireMaxProb" :unit="'%'" :inputType="'number'" :label="'着火最大概率'" :min="0" :max="100"></LabelInput>
        <LabelInput v-model="windPower" :unit="'级'" :inputType="'number'"  :label="'风力'" :min="0" :max="17"></LabelInput>
        <LabelInput v-if="windPower > 0" v-model="windDirection" :unit="'°'" :inputType="'number'"  :label="'风向'" :min="0" :max="359"></LabelInput>
    </PopList>
</template>

<script setup lang="ts">
import { ref, reactive, inject, onBeforeUnmount } from "vue";
import PopList from "../../../components/PopList.vue";
import LabelInput from "../../../components/LabelInput.vue";
import { XbsjEarthUi } from "../../../scripts/xbsjEarthUi";
import { ESLocalCircle, ESSceneObject } from "esobjs-xe2-plugin/dist-node/esobjs-xe2-plugin-main";
import { Message } from 'earthsdk-ui';

const xbsjEarthUi = inject('xbsjEarthUi') as XbsjEarthUi;
const cellSize = ref(80); // 单元格大小(米)
const gridSize = ref(1000); // 网格总大小(米)
const spreadMaxTimes = ref(5);  //蔓延趋势计算次数
const spreadFrequency = ref(1); //蔓延趋势计算频率，单位秒
const fireMaxProb = ref(40); //建筑着火概率最大值
const windPower = ref(0); //风力大小
const windDirection = ref(90); //风力方向
let cellMap = reactive({})

class EsCellular extends ESSceneObject{
    static readonly type = this.register('EsCellular', this, { chsName: 'EsCellular', tags: ['ESObjects', '_ES_Impl_UE'], description: "EsCellular" });
    get typeName() { return 'EsCellular'; }

    x: number
    y: number
    prob: number    // 着火概率 从 0 - 100
    status: number  // 着火状态 0:未着火; 1:已着火
    burn_time: Date|undefined // 着火时间 超过一定时间后不再影响周围
    power: number   // 火势 默认为 0 越大概率影响周边的概率越高
    treeItem: any   //场景树节点
    spreadTimer: NodeJS.Timeout | undefined  //定时器
    spreadTimes: number   //蔓延尝试次数
    json: string | any

    static override defaults = {
        ...ESSceneObject.defaults,
        status: 0,
        power: 0,
        spreadTimes: 0,
    };

    constructor(id?: string) {
        super(id)
        this.status = 0
        this.power = 0
        this.spreadTimes = 0
    }
    
    // 计算着火概率
    calcFire() {
        let p = Math.fround(Math.random() * 100);
        // console.log('<<<>>>',p <= this.prob, p, this.prob )
        return p <= this.prob;
    }

    onFire(force = false): void {
        // console.log(force, this.status, this.x, this.y )
        // 已着火则退出
        if(this.status === 1) return
        // 非强制点火，则计算着火概率，不满足条件则返回
        if(!force && !this.calcFire()) return;
        this.burn_time = new Date()
        this.power = 1
        this.status = 1
        this.treeItem.sceneObject.fillColor = [1, 0, 0, 1]
        let that = this
        this.spreadTimer = setInterval(function () {
            that.spreadTimes ++;
            if(that.spreadTimes > spreadMaxTimes.value) {
                clearInterval(that.spreadTimer);
                return;
            }
            that.spread(that)
        }, spreadFrequency.value * 1000)
    }

    spread(me: EsCellular): void {
        console.log('spread', me.x, me.y)
        let northCell: EsCellular = me.getNorth();
        northCell && northCell.onFire();
        let southCell: EsCellular = me.getSouth();
        southCell && southCell.onFire();
        let eastCell: EsCellular = me.getEast();
        eastCell && eastCell.onFire();
        let westCell: EsCellular = me.getWest();
        westCell && westCell.onFire();
    }

    getNorth():EsCellular {
        return getGrid( this.x, this.y - 1)
    }

    getSouth():EsCellular {
        return getGrid( this.x, this.y + 1)
    }

    getEast():EsCellular {
        return getGrid( this.x - 1, this.y)
    }

    getWest():EsCellular {
        return getGrid( this.x + 1, this.y)
    }

    init(prob:number, x:number, y:number, treeItem:any) {
        this.prob = prob 
        this.x = x;
        this.y = y;
        this.treeItem = treeItem
        this.status = 0
        this.power = 0
        this.spreadTimes = 0
        this.treeItem.sceneObject.filled = true;
        this.treeItem.sceneObject.stroked = true;
        this.treeItem.sceneObject.strokeWidth = 2;
        if(this.prob < 10){
            this.treeItem.sceneObject.fillColor = [200/255, 200/255, 200/255, .2];
            this.treeItem.sceneObject.strokeColor = [200/255, 200/255, 200/255, 1];
        }
        else if(this.prob < 30) {
            this.treeItem.sceneObject.fillColor = [175/255, 220/255, 205/255, .2];
            this.treeItem.sceneObject.strokeColor = [175/255, 220/255, 205/255, 1];
        }
        else{
            this.treeItem.sceneObject.fillColor = [80/255, 255/255, 15/255, .2];
            this.treeItem.sceneObject.strokeColor = [80/255, 255/255, 15/255, 1];
        }
        
        this.dispose(() => {
            console.log(1)
            this.treeItem.sceneObj.destroy()
        });
    }

    destroy(): undefined {
        
    }
}

// 经纬度转墨卡托
function lngLatToMercator(lng: number, lat: number) {
    const x = lng * 20037508.34 / 180;
    let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
    y = y * 20037508.34 / 180;
    return [x, y];
}

// 墨卡托转经纬度
function mercatorToLngLat(x: number, y: number) {
    const lng = x * 180 / 20037508.34;
    let lat = y * 180 / 20037508.34;
    lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
    return [lng, lat];
}

// 创建网格
const createGrid = () => {
    destroy()
    const sceneTree = xbsjEarthUi.getSceneTree();
    if (!sceneTree) return;

    // 创建"元胞网格"图层节点
    let folderItem = sceneTree.json.root.children?.find(item =>
        item.name === '元胞网格'
    );
    if (folderItem) {
        // 删除树节点，节点上的对象也会从场景内被删除；
        sceneTree.destroySceneObjectTreeItem(folderItem)
    }
    folderItem = sceneTree.createGroupTreeItem('元胞网格');

    const center = [118.30712, 32.30607]; // 苏宁广场坐标
    const [centerX, centerY] = lngLatToMercator(center[0], center[1]);

    const rows = Math.floor(gridSize.value / cellSize.value);
    const cols = rows;

    const halfGrid = gridSize.value / 2;

    for(let i = 0; i < rows; i++) {
        for(let j = 0; j < cols; j++) {

            const x = centerX - halfGrid + (j + 0.5) * cellSize.value;
            const y = centerY - halfGrid + (i + 0.5) * cellSize.value;

            const [lng, lat] = mercatorToLngLat(x, y);

            const circle = xbsjEarthUi.createSceneObject(ESLocalCircle);
            if(!circle) continue;
            const fireProbability = Math.round( Math.random() * fireMaxProb.value);

            circle.name = `Cell_${i}_${j}`;
            circle.position = [lng, lat, 300];
            circle.radius = cellSize.value / 3;
            // circle.fillGround = true; // 贴地
            const json = JSON.parse(circle.jsonStr);
            // xbsjEarthUi.destroySceneObject(circle);

            // 将网格创建到文件夹中
            let treeItem = sceneTree.createSceneObjectTreeItemFromJson(json, folderItem, 'Inner')

            let cellular = new EsCellular();
            cellular.init(fireProbability, i ,j, treeItem);
            let cellX = cellMap[i]
            if (!cellX) cellX = {}
            cellX[j] = cellular
            cellMap[i] = cellX
        }
    }
    console.log(cellMap)

    Message.success('网格创建完成');
}

// 根据x，y 获取单元格
const getGrid = (x: number, y: number) => {
    let cellX = cellMap[x]
    if( !cellX ) return;
    let cell = cellX[y]
    if( !cell ) return;
    return cell;
}

// 随机点火
const onFire = () => {
    let x = Math.floor(Math.random() * Object.keys(cellMap).length);
    if(x === 0) return;
    let y = Math.floor(Math.random() * Object.keys(cellMap[x]).length);
    let cell = cellMap[x][y]
    // 强制点火
    cell.onFire(true)
}

const reset = () => {
    cellMap.forEach((cellMapY) => {
        cellMapY.forEach((cell) => {
            cell.init();
        })
    })

}

const destroy = () => {
    // 清理相关资源
    const sceneTree = xbsjEarthUi.getSceneTree();
    if (!sceneTree) return;

    // 删除"元胞网格"文件夹及其内容
    const folderItem = sceneTree.json.root.children?.find(item =>
        item.name === '元胞网格'
    ); 
    console.log(folderItem)
    console.log(xbsjEarthUi)
    if (folderItem) {
        sceneTree.destroySceneObjectTreeItem(folderItem)
    }
}

onBeforeUnmount(() => {
    destroy();
})
</script> 